/*
 * @Author: 陈俊升 761723995@qq.com
 * @Date: 2023-05-11 08:47:22
 * @LastEditors: 陈俊升 761723995@qq.com
 * @LastEditTime: 2024-01-02 15:49:01
 * @FilePath: /hr_new_vue3/src/utils/file.ts
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * 文件相关的方法
 */

import printJS from 'print-js';
import type { Configuration } from 'print-js';
import dayjs from 'dayjs';
type PrintTypes = 'pdf' | 'html' | 'image' | 'json' | 'raw-html';

import { getFileDelong } from '@/apis/document/documentCenter/index';
import {
  PostFile,
  postFileUpload,
  postFileUploadManagement
} from '@/apis/management/base/index';
import JSZip from 'jszip';
import FileSaver from 'file-saver';

// //选择文件
// export const openChoiceFile = (fileTypeList: string[], size?: number) => {
//   return new Promise<File>((resolve, reject) => {
//     let input: HTMLInputElement | undefined = document.createElement('input');
//     input.type = 'file';
//     input.accept = fileTypeList.join(',');
//     input.multiple = false;
//     input.onchange = (e: any) => {
//       const file: File = e.target.files[0];
//       // 判断文件大小
//       if (size && file.size > size) {
//         reject(
//           new Error('超出大小限制,不可超过' + (size / 1048576).toFixed(2) + 'M')
//         );
//         return;
//       }
//       //判断文件类型
//       if (fileTypeList) {
//         let checkType = false;
//         for (const type of fileTypeList) {
//           if (file.name.indexOf(type) !== -1) {
//             checkType = true;
//           }
//         }
//         if (!checkType) {
//           reject(new Error('文件类型错误'));
//           return;
//         }
//       }
//       input = undefined; // 释放dom，避免内存泄漏
//       resolve(file); // 输出文件
//     };
//     input.click();
//   });
// };

// 单文件下载

export function downloadFile(url: string, filename: string) {
  const anchorElement = document.createElement('a');
  anchorElement.href = url;
  anchorElement.download = filename;
  anchorElement.click();
}

// 多文件下载
export function downloadFiles(fileDataArray: any[], zipName = '压缩包') {
  const blogTitle = zipName; // 下载后压缩包的命名
  const zip = new JSZip();
  const promises = [];
  const cache: any = {};
  const arrImg = [];
  for (let i = 0; i < fileDataArray.length; i++) {
    arrImg.push({
      path: fileDataArray[i].url, // 文件链接
      name: fileDataArray[i].name // 文件名称
    });
  }
  for (const item of arrImg) {
    // item.path为文件链接地址
    const promise = getImgArrayBuffer(item.path).then((data: any) => {
      // 下载文件, 并存成ArrayBuffer对象(blob)
      zip.file(item.name, data, { binary: true }); // 逐个新增文件
      cache[item.name] = data;
    });
    promises.push(promise);
  }
  Promise.all(promises)
    .then(() => {
      zip.generateAsync({ type: 'blob' }).then((content) => {
        // 生成二进制流
        FileSaver.saveAs(content, blogTitle); // 利用file-saver保存文件  自定义文件名
      });
    })
    .catch((res) => {
      alert('文件压缩失败');
    });
}

//文件以流的形式获取（参数url为文件链接地址）
function getImgArrayBuffer(url: string | URL) {
  return new Promise((resolve, reject) => {
    //通过请求获取文件blob格式
    const xmlhttp = new XMLHttpRequest();
    xmlhttp.open('GET', url, true);
    xmlhttp.responseType = 'blob';
    xmlhttp.onload = function () {
      if (this.status == 200) {
        resolve(this.response);
      } else {
        reject(this.status);
      }
    };
    xmlhttp.send();
  });
}

// 批量打印文件
/* 
  fileDataArray: [
    {
      url: 'https://www.baidu.com/img/flexible/logo/pc/result@2.png',
    }
  ]
*/
export async function printFiles(fileDataArray: any[]) {
  for (let i = 0; i < fileDataArray.length; i++) {
    const type = getFileExtension(fileDataArray[i]?.url) as PrintTypes;
    printJS({
      printable: fileDataArray[i]?.url,
      type
    });
    await new Promise((resolve) => setTimeout(resolve, 1000)); // 等待一段时间后再打印下一个文件
  }
}

// 截取文件后缀名(遇到图片后缀的直接转换成image)
function getFileExtension(filename: string) {
  const extension = filename.slice(filename.lastIndexOf('.') + 1).toLowerCase();
  const imageEnums = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'];
  if (imageEnums.includes(extension)) {
    return 'image';
  }
  return extension;
}

// 截取文件后缀名
export function getFileSuffix(filename: string) {
  const extension = filename.slice(filename.lastIndexOf('.') + 1).toLowerCase();
  return extension;
}

/**
 * @param fileTypeList 文件后缀列表，如['.png','.jpg']
 * @param selectNum 选择数量 1和0为单选 其余多选
 * @param size 文件大小限制 5m的话为 5*1025*1024
 * @returns Promise<File[]>
 */
export const openChoiceFile = (
  fileTypeList: string[],
  selectNum: number,
  size?: number
) => {
  return new Promise<File[]>((resolve, reject) => {
    let input: HTMLInputElement | undefined = document.createElement('input');
    input.type = 'file';
    input.accept = fileTypeList.join(',');
    input.multiple = !(!selectNum || selectNum === 1); //判断是否多选
    input.onchange = (e: any) => {
      const fileListObj = e.target.files;
      //校验选择文件数量
      if (fileListObj.length > selectNum) {
        reject(`只能上传${selectNum}份文件`);
        return (input = undefined); //释放dom，避免内存泄漏
      }
      const fileList: File[] = [];
      //循环FileLists实例，FileLists不是数组只能用普通for循环
      for (let i = 0; i < fileListObj.length; i++) {
        const file = fileListObj.item(i);
        //如果size有传，校验文件大小
        if (size && file.size > size) {
          reject(new Error(`文件过大,不可超过${(size / 1048576).toFixed(2)}M`));
          return (input = undefined); // 释放dom，避免内存泄漏
        }
        //校验文件类型
        const fileType = file.name.slice(file.name.lastIndexOf('.'));
        if (!fileTypeList.includes(fileType)) {
          reject(new Error('文件类型错误'));
          return (input = undefined); // 释放dom，避免内存泄漏
        }
        fileList.push(file);
      }
      resolve(fileList); // 输出文件列表
      input = undefined; // 释放dom，避免内存泄漏
    };
    input.click();
  });
};

//'img' | 'officeFile' | 'vidoe' | 'audio' | 'other'
export const imgTypeList = ['.jpeg', '.png', '.gif', '.jpg']; //图片类型

export const officeTypeList = [
  '.doc',
  '.docx',
  '.xls',
  '.xlsx',
  '.ppt',
  '.pptx',
  '.pdf',
  '.txt',
  '.rar'
]; //文档类型
export const vidoeTypeList = ['.mp4', '.mkv']; //视频类型

export const audioTypeList = ['.mp3']; //音频类型

//获取视频时长
export const getVideoDuration = (file: File) => {
  return new Promise<string>((resolve) => {
    const viodUrl = URL.createObjectURL(file);
    let video: HTMLVideoElement | undefined = document.createElement('video');
    video.src = viodUrl;
    video.onloadedmetadata = () => {
      resolve(Math.floor(video?.duration ? video.duration : 0 / 60) + '');
      video = undefined;
    };
  });
};

//获取音频时长
export const getAudioDuration = (file: File) => {
  return new Promise<string>((resolve) => {
    const viodUrl = URL.createObjectURL(file);
    let audio: HTMLAudioElement | undefined = new Audio(viodUrl);
    audio.onloadedmetadata = () => {
      resolve(Math.floor(audio?.duration ? audio.duration : 0 / 60) + '');
      audio = undefined;
    };
  });
};
const userId = +(localStorage.getItem('userId') + '');

/**
 * 聊天上传图片
 * @param file Blob
 * @returns URL
 */
export const MessageFile = async (file: string) => {
  try {
    const dataArr = file.split(',');
    const byteString = window.atob(dataArr[1]);
    const options: FilePropertyBag = {
      type: 'image/jpeg',
      endings: 'native'
    };
    const u8Arr = new Uint8Array(byteString.length);
    for (let i = 0; i < byteString.length; i++) {
      u8Arr[i] = byteString.charCodeAt(i);
    }
    const blob = new File([u8Arr], '.jpg', options); //返回文件流
    const formData = new FormData();
    const fileBelongId = await fileLocation();
    formData.append('file', blob); //文件本身
    formData.append('fileStart', 0 as any); //断点传续文件起始点
    formData.append('endFlag', '2'); //文件上传结束标识 1未完成 2完成
    formData.append('userId', userId as any); //对象id
    formData.append('fileBelongId', fileBelongId); //文件分类id
    formData.append(
      'useFileName',
      `${+new Date()}-${dayjs(new Date()).format('YYYY/MM/DD')}.png`
    ); //文件名
    formData.append('filePath', `${userId}/根目录/聊天记录`);
    formData.append('fileType', '1');
    formData.append('fileSize', blob.size as any); //文件大小（单位：KB）
    formData.append('fileStorageLocal', 2 as any); //文件展现定位
    formData.append('fileAttribute', 2 as any);
    const res = await postFileUploadManagement(formData);
    return Promise.resolve(res.fileUrl);
  } catch (error) {
    console.log(error);
    return Promise.reject('失败');
  }
};

export const fileLocation = async () => {
  const res = await getFileDelong({ userId: userId });
  const id = flattenTree([res]).filter(
    ({ storeName }: any) => storeName === '聊天记录'
  )[0]?.id;
  if (id) return id;
  else return 0;
};

const flattenTree: any = (tree: any) => {
  let flattened: any = [];
  for (let i = 0; i < tree.length; i++) {
    const node = tree[i];
    const flattenedNode = {
      id: node.id,
      storeName: node.storeName,
      parent: parent
    };
    flattened.push(flattenedNode);
    if (node.children && node.children.length > 0) {
      const children = flattenTree(node.children, node.id);
      flattened = flattened.concat(children);
    }
  }
  return flattened;
};
const defaultFlag = 10 * 1024 * 1024;
const defaultChunkSize = 10 * 1024 * 1024;

/**
 * 文件上传
 * @param file Blob
 * @returns URL
 */
export const UpLoadFile = async (
  file: File,
  flag = defaultFlag,
  chunkSize = defaultChunkSize
) => {
  try {
    const fileBelongId = await fileLocation();
    if (file.size <= flag) {
      const formData = new FormData();
      formData.append('file', file); //文件本身
      formData.append('fileStart', 0 as any); //断点传续文件起始点
      formData.append('endFlag', '2'); //文件上传结束标识 1未完成 2完成
      formData.append('userId', userId as any); //对象id
      formData.append('fileBelongId', fileBelongId); //文件分类id
      formData.append(
        'useFileName',
        `${+new Date()}-${dayjs(new Date()).format(
          'YYYY/MM/DD'
        )}.${file.name.slice(file.name.lastIndexOf('.'))}`
      ); //文件名
      formData.append('filePath', `${userId}/根目录/聊天记录`);
      formData.append('fileType', '1');
      formData.append('fileSize', file.size as any); //文件大小（单位：KB）
      formData.append('fileStorageLocal', 2 as any); //文件展现定位
      formData.append('fileAttribute', 2 as any);
      const res = await postFileUploadManagement(formData);
      return Promise.resolve(res.fileUrl);
    } else {
      let currentChunk = 0;
      let start = currentChunk * chunkSize;
      let end = Math.min(start + chunkSize, file.size);
      let fileName = null;
      let fileUrl = null;
      while (start < file.size) {
        const chunk = file.slice(start, end);
        if (!fileName) {
          const res = await sectionFile(file, chunk, start, true);
          fileName = res.fileName;
        } else {
          const res = await sectionFile(
            file,
            chunk,
            start,
            end === file.size ? false : true,
            fileName
          );
          fileName = res.fileName;
          if (res.fileUrl) {
            fileUrl = res.fileUrl;
          }
        }
        start = end;
        end = Math.min(start + chunkSize, file.size);
        currentChunk++;
      }
      return Promise.resolve(fileUrl);
    }
  } catch (error) {
    console.log(error);
    return Promise.reject('失败');
  }
};

const sectionFile = async (
  file: File,
  section: Blob,
  start: number,
  end: boolean,
  fileName?: string
): Promise<{ fileUrl?: string | undefined; fileName: string }> => {
  const fileBelongId = await fileLocation();
  const formData = new FormData();
  formData.append('file', section); //文件本身
  formData.append('fileStart', start as any); //断点传续文件起始点
  formData.append('endFlag', end ? '1' : '2'); //文件上传结束标识 1未完成 2完成
  formData.append('userId', userId as any); //对象id
  formData.append('fileBelongId', fileBelongId); //文件分类id
  formData.append(
    'useFileName',
    `${+new Date()}-${dayjs(new Date()).format('YYYY/MM/DD')}.${file.type
      .split('/')
      .pop()}`
  ); //文件名
  if (fileName) formData.append('fileName', fileName); //文件名
  formData.append('filePath', `${userId}/根目录/聊天记录`);
  formData.append('fileType', '1');
  formData.append('fileSize', file.size as any); //文件大小（单位：KB）
  formData.append('fileStorageLocal', 2 as any); //文件展现定位
  formData.append('fileAttribute', 2 as any);
  const res = await postFileUploadManagement(formData);
  return Promise.resolve(res);
};

export const avatarSetting = async (file: string) => {
  try {
    const dataArr = file.split(',');
    const byteString = window.atob(dataArr[1]);
    const options: FilePropertyBag = {
      type: 'image/jpeg',
      endings: 'native'
    };
    const u8Arr = new Uint8Array(byteString.length);
    for (let i = 0; i < byteString.length; i++) {
      u8Arr[i] = byteString.charCodeAt(i);
    }
    const blob = new File([u8Arr], '.jpg', options); //返回文件流
    const formData = new FormData();
    const fileBelongId = await fileLocation();
    formData.append('file', blob); //文件本身
    formData.append('fileStart', 0 as any); //断点传续文件起始点
    formData.append('endFlag', '2'); //文件上传结束标识 1未完成 2完成
    formData.append('userId', userId as any); //对象id
    formData.append('fileBelongId', fileBelongId); //文件分类id
    formData.append(
      'useFileName',
      `${+new Date()}-${dayjs(new Date()).format('YYYY/MM/DD')}.png`
    ); //文件名
    formData.append('filePath', `${userId}/根目录/聊天记录`);
    formData.append('fileType', '1');
    formData.append('fileSize', blob.size as any); //文件大小（单位：KB）
    formData.append('fileStorageLocal', 2 as any); //文件展现定位
    formData.append('fileAttribute', 2 as any);
    const res = await PostFile(formData);
    return Promise.resolve(res.DownloadPath);
  } catch (error) {
    console.log(error);
    return Promise.reject('失败');
  }
};
